/**
 * echarts地图一般投射算法
 * modify from GeoMap v0.5.3 https://github.com/x6doooo/GeoMap
 * 
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */


function getBbox(json, specialArea) {
    specialArea = specialArea || {};
    if (!json.srcSize) {
        parseSrcSize(json, specialArea);
    }
    return json.srcSize;
}
function parseSrcSize(json, specialArea) {
    specialArea = specialArea || {};
    convertorParse.xmin = 360;
    convertorParse.xmax = -360;
    convertorParse.ymin = 180;
    convertorParse.ymax = -180;
    var shapes = json.features;
    var geometries;
    var shape;
    for (var i = 0, len = shapes.length; i < len; i++) {
        shape = shapes[i];
        if (shape.properties.name && specialArea[shape.properties.name]) {
            continue;
        }
        switch (shape.type) {
        case 'Feature':
            convertorParse[shape.geometry.type](shape.geometry.coordinates);
            break;
        case 'GeometryCollection':
            geometries = shape.geometries;
            for (var j = 0, len2 = geometries.length; j < len2; j++) {
                convertorParse[geometries[j].type](geometries[j].coordinates);
            }
            break;
        }
    }
    json.srcSize = {
        left: convertorParse.xmin.toFixed(4) * 1,
        top: convertorParse.ymin.toFixed(4) * 1,
        width: (convertorParse.xmax - convertorParse.xmin).toFixed(4) * 1,
        height: (convertorParse.ymax - convertorParse.ymin).toFixed(4) * 1
    };
    return json;
}
var convertor = {
    //调整俄罗斯东部到地图右侧与俄罗斯相连
    formatPoint: function (p) {
        return [
            (p[0] < -168.5 && p[1] > 63.8 ? p[0] + 360 : p[0]) + 168.5,
            90 - p[1]
        ];
    },
    makePoint: function (p) {
        var self = this;
        var point = self.formatPoint(p);
        // for cp
        if (self._bbox.xmin > p[0]) {
            self._bbox.xmin = p[0];
        }
        if (self._bbox.xmax < p[0]) {
            self._bbox.xmax = p[0];
        }
        if (self._bbox.ymin > p[1]) {
            self._bbox.ymin = p[1];
        }
        if (self._bbox.ymax < p[1]) {
            self._bbox.ymax = p[1];
        }
        var x = (point[0] - convertor.offset.x) * convertor.scale.x + convertor.offset.left;
        var y = (point[1] - convertor.offset.y) * convertor.scale.y + convertor.offset.top;
        return [
            x,
            y
        ];
    },
    Point: function (coordinates) {
        coordinates = this.makePoint(coordinates);
        return coordinates.join(',');
    },
    LineString: function (coordinates) {
        var str = '';
        var point;
        for (var i = 0, len = coordinates.length; i < len; i++) {
            point = convertor.makePoint(coordinates[i]);
            if (i === 0) {
                str = 'M' + point.join(',');
            } else {
                str = str + 'L' + point.join(',');
            }
        }
        return str;
    },
    Polygon: function (coordinates) {
        var str = '';
        for (var i = 0, len = coordinates.length; i < len; i++) {
            str = str + convertor.LineString(coordinates[i]) + 'z';
        }
        return str;
    },
    MultiPoint: function (coordinates) {
        var arr = [];
        for (var i = 0, len = coordinates.length; i < len; i++) {
            arr.push(convertor.Point(coordinates[i]));
        }
        return arr;
    },
    MultiLineString: function (coordinates) {
        var str = '';
        for (var i = 0, len = coordinates.length; i < len; i++) {
            str += convertor.LineString(coordinates[i]);
        }
        return str;
    },
    MultiPolygon: function (coordinates) {
        var str = '';
        for (var i = 0, len = coordinates.length; i < len; i++) {
            str += convertor.Polygon(coordinates[i]);
        }
        return str;
    }
};
var convertorParse = {
    formatPoint: convertor.formatPoint,
    makePoint: function (p) {
        var self = this;
        var point = self.formatPoint(p);
        var x = point[0];
        var y = point[1];
        if (self.xmin > x) {
            self.xmin = x;
        }
        if (self.xmax < x) {
            self.xmax = x;
        }
        if (self.ymin > y) {
            self.ymin = y;
        }
        if (self.ymax < y) {
            self.ymax = y;
        }
    },
    Point: function (coordinates) {
        this.makePoint(coordinates);
    },
    LineString: function (coordinates) {
        for (var i = 0, len = coordinates.length; i < len; i++) {
            this.makePoint(coordinates[i]);
        }
    },
    Polygon: function (coordinates) {
        for (var i = 0, len = coordinates.length; i < len; i++) {
            this.LineString(coordinates[i]);
        }
    },
    MultiPoint: function (coordinates) {
        for (var i = 0, len = coordinates.length; i < len; i++) {
            this.Point(coordinates[i]);
        }
    },
    MultiLineString: function (coordinates) {
        for (var i = 0, len = coordinates.length; i < len; i++) {
            this.LineString(coordinates[i]);
        }
    },
    MultiPolygon: function (coordinates) {
        for (var i = 0, len = coordinates.length; i < len; i++) {
            this.Polygon(coordinates[i]);
        }
    }
};
function geoJson2Path(json, transform, specialArea) {
    specialArea = specialArea || {};
    convertor.scale = null;
    convertor.offset = null;
    if (!json.srcSize) {
        parseSrcSize(json, specialArea);
    }
    transform.offset = {
        x: json.srcSize.left,
        y: json.srcSize.top,
        left: transform.OffsetLeft || 0,
        top: transform.OffsetTop || 0
    };
    convertor.scale = transform.scale;
    convertor.offset = transform.offset;
    var shapes = json.features;
    var geometries;
    var pathArray = [];
    var val;
    var shape;
    for (var i = 0, len = shapes.length; i < len; i++) {
        shape = shapes[i];
        if (shape.properties.name && specialArea[shape.properties.name]) {
            // 忽略specialArea
            continue;
        }
        if (shape.type == 'Feature') {
            pushApath(shape.geometry, shape);
        } else if (shape.type == 'GeometryCollection') {
            geometries = shape.geometries;
            for (var j = 0, len2 = geometries.length; j < len2; j++) {
                val = geometries[j];
                pushApath(val, val);
            }
        }
    }
    var shapeType;
    var shapeCoordinates;
    var str;
    function pushApath(gm, shape) {
        shapeType = gm.type;
        shapeCoordinates = gm.coordinates;
        convertor._bbox = {
            xmin: 360,
            xmax: -360,
            ymin: 180,
            ymax: -180
        };
        str = convertor[shapeType](shapeCoordinates);
        pathArray.push({
            // type: shapeType,
            path: str,
            cp: shape.properties.cp ? convertor.makePoint(shape.properties.cp) : convertor.makePoint([
                (convertor._bbox.xmin + convertor._bbox.xmax) / 2,
                (convertor._bbox.ymin + convertor._bbox.ymax) / 2
            ]),
            properties: shape.properties,
            id: shape.id
        });
    }
    return pathArray;
}
/**
     * 平面坐标转经纬度
     * @param {Array} p
     */
function pos2geo(obj, p) {
    var x;
    var y;
    if (p instanceof Array) {
        x = p[0] * 1;
        y = p[1] * 1;
    } else {
        x = p.x * 1;
        y = p.y * 1;
    }
    x = x / obj.scale.x + obj.offset.x - 168.5;
    x = x > 180 ? x - 360 : x;
    y = 90 - (y / obj.scale.y + obj.offset.y);
    return [
        x,
        y
    ];
}
/**
     * 经纬度转平面坐标
     * @param {Array | Object} p
     */
function geo2pos(obj, p) {
    convertor.offset = obj.offset;
    convertor.scale = obj.scale;
    return p instanceof Array ? convertor.makePoint([
        p[0] * 1,
        p[1] * 1
    ]) : convertor.makePoint([
        p.x * 1,
        p.y * 1
    ]);
}
module.exports = {
    getBbox: getBbox,
    geoJson2Path: geoJson2Path,
    pos2geo: pos2geo,
    geo2pos: geo2pos
} || module.exports;;